package cn.sylinx.horm.model.base;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import cn.sylinx.horm.exception.HORMException;
import cn.sylinx.horm.model.cache.ModelCacheUtil;
import cn.sylinx.horm.model.lambda.TypeFunction;
import cn.sylinx.horm.util.LambdaUtil;

@SuppressWarnings("unchecked")
public class Model implements Serializable, Cloneable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private static final String NULLABLE_FIELDS = "NULLABLE_FIELDS";
    /**
     * 自定义属性
     */
    private Map<String, Object> context = new HashMap<String, Object>();

    public Map<String, Object> getContext() {
        return context;
    }

    /**
     * 对应属性可设置为空
     * 
     * @param attributeName
     * @return
     */
    public <T extends Model> T withNullable(String attributeName) {
        getNullableFields().add(attributeName);
        return (T) this;
    }

    /**
     * 对应属性可设置为空
     * 
     * @param <T>
     * @param <R>
     * @param lambda
     * @return
     */
    public <T extends Model, R> T withNullable(TypeFunction<T, R> lambda) {
        return withNullable(LambdaUtil.getLambdaFieldName(lambda));
    }

    /**
     * 对应属性可设置为空
     * 
     * @param attributeNames
     * @return
     */
    public <T extends Model> T withNullables(String... attributeNames) {
        if (attributeNames != null) {
            for (String attributeName : attributeNames) {
                getNullableFields().add(attributeName);
            }
        }
        return (T) this;
    }

    /**
     * 对应属性可设置为空
     * 
     * @param <T>
     * @param <R>
     * @param lambdaArray
     * @return
     */
    public <T extends Model, R> T withNullables(TypeFunction<T, R>... lambdaArray) {

        for (int i = 0; i < lambdaArray.length; ++i) {
            getNullableFields().add(LambdaUtil.getLambdaFieldName(lambdaArray[i]));
        }

        return (T) this;
    }

    /**
     * 清空可空字段
     * 
     * @return
     */
    public <T extends Model> T removeNullable() {
        getNullableFields().clear();
        return (T) this;
    }

    /**
     * 将所有字段可设置为空
     * 
     * @return
     */
    public <T extends Model> T withNullable() {
        List<Field> fieldList = ModelCacheUtil.getObjectAllFieldsWithcache(getClass());
        for (Field f : fieldList) {
            withNullable(f.getName());
        }
        return (T) this;
    }

    /**
     * 获取所有可设置空字段
     * 
     * @return
     */
    public Set<String> getNullableFields() {
        Object object = context.get(NULLABLE_FIELDS);
        if (object == null) {
            object = new HashSet<String>();
            context.put(NULLABLE_FIELDS, object);
        }

        return (Set<String>) object;
    }

    @Override
    public Object clone() {

        Model cloneObject = null;
        try {
            cloneObject = (Model) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new HORMException(e);
        }

        if (cloneObject != null) {
            cloneObject.context = new HashMap<String, Object>();
            // 深度克隆 context
            Iterator<Entry<String, Object>> iterator = context.entrySet().iterator();
            while (iterator.hasNext()) {
                Entry<String, Object> entry = iterator.next();
                cloneObject.context.put(entry.getKey(), entry.getValue());
            }
        }

        return cloneObject;
    }

}
